(function($){
/*TODO:
 * Break this up into multiple files
 */
 
jQuery.fn.hasChild = function (child) {
    child = child || null;
    return this.children(child).length > 0;
};
 
jQuery.fn.getIdSelectors = function (modify) {
    modify = modify || function(x) { return x; };
    return $(this).map(function() {
        return "#" + modify($(this).attr("id"));
    }).toArray().join(",");
};

jQuery.fn.formOptions = function () {
    var hash = $(window.location.hash);
        hash = hash.length > 0 ? hash : null;
        
    var target = function(el) { 
        return $($(el).getIdSelectors(function(id) { 
            return id.replace(/-select$/, ""); 
        }));
    };
    
    var selector = function (el) {
        return $("#" + $(el).attr("id") + "-select");
    };
    
    this.each(function() {
        var $this   = $(this);
        var select  = $this.children(".method-selection");
        var more    = $this.children(".options");
        select.find("input").change(function(e) {
            more.filter(":not(:checked)").hide();
            target(e.target).show();
        });
        
        if(hash && $this.hasChild(hash)) {
            selector(hash).attr("checked", true);
        }
        
        more.hide();
        target(select.find(":checked")).show();
    });
};

jQuery.fn.formSlider = function (options) {
    this.each(function(i, el){
        var input  = $(el).children("input");
        var val    = input.val(),
            min    = parseFloat(input.attr("min")),
            max    = parseFloat(input.attr("max")),
            step   = input.attr("step");
        var slider = $('<div class="slider">')
                    .attr("id", input.attr("id")+"-slider")
                    .prependTo(el);
        var places = $(el).hasClass("int") ? 0 : 2;
        slider.slider({
            value: val ? val : 0,
            min:   min,
            max:   max,
            step:  step ? parseFloat(step) : (max - min) / 100,
            slide: function(e, ui) {
                input.val(parseFloat(ui.value).toFixed(places));
            }
        });
        input.change(function(e){
            slider.slider("value", input.val());
        });
    });
};

jQuery.fn.formRangeSlider = function (options) {
    this.each(function(i, el){
        var $this  = $(el);
        var min    = $this.find("input.min"),
            max    = $this.find("input.max");
        var limits = [parseFloat(min.attr("min")), parseFloat(max.attr("max"))],
            values = [parseFloat(min.val()), parseFloat(max.val())],
            step   = min.attr("step");
        var slider = $('<div class="slider">')
                    .attr("id", $this.attr("id")+"-slider")
                    .appendTo($this);
        var places = $this.hasClass("int") ? 0 : 2;
        slider.slider({
            range:  true,
            values: values,
            min:   limits[0],
            max:   limits[1],
            step:  step ? parseFloat(step) : (limits[1] - limits[0]) / 100,
            slide: function(e, ui) {
                min.val(parseFloat(ui.values[0]).toFixed(places));
                max.val(parseFloat(ui.values[1]).toFixed(places));
            }
        });
        $([min, max]).change(function(){
            slider.slider("values", [
                parseFloat(min.val()), 
                parseFloat(max.val())
            ]);
        });
    });
};

jQuery.fn.formEnableTextField = function (toggler, togglable, globalToggle) {
    this.each(function(i, el) {
        var $this = $(el),
            target,
            trigger;
            
        if(globalToggle === true) {
            trigger = $(toggler);
            target  = $(togglable);
        } else {
            trigger = $this.find(toggler);
            target  = $this.find(togglable).add(globalToggle);
        }
        
        trigger.change(function() {
            if($(this).attr("checked")) {
                target.removeAttr("disabled").focus().parent().removeClass("disabled");
            } else {
                target.attr("disabled", true).parent().addClass("disabled");
            }            
        }).trigger("change");
    });
};

jQuery.fn.wiceProjectPresets = function (fields, project) {
    if(project) {
        fields.children("a").filter(":not(.projects)").attr("rel", project.external);
        var toolType = $("body").attr("id");
        if(project[toolType]) {
            var parameters =  $("form.job-details input");
            jQuery.each(project[toolType], function(name, value) {
                console.log(name + " = " + value);
                parameters.filter("[name="+name+"]").val(value).trigger("change");
                
                console.log(parameters.filter("[name="+name+"]"));
            });
        }
    } else {
        fields.children("a").filter(":not(.projects)").attr("rel", "~");
    }
};

jQuery.fn.autocompleteBrowser = function (browser) {

    var fields         = this;
    var targetStore    = "autocomplete-browser-destination";
    var typeStore      = "autocomplete-browser-type";   
    var projectStore   = "autocomplete-project";
    var contentsSource = "directory-listings.php";
    
    // Build Dialog Structures
    var directories = $('<ul class="directories">');
    var selected    = $('<input id="file-browser-selected-file" readonly>');
    var details     = $('<table class="contents-detail-listing">').append(
                            $('<thead>').append(
                                $('<tr>').append(
                                    $('<th class="path">Path</th>'),
                                    $('<th class="name">Name</th>'),
                                    $('<th class="date">Created</th>'))));
    var browser     = 
        $('<div id="file-browser" class="file-browser">').append(
            $('<div class="browser">').append(directories,
                $('<div class="directory-contents">').append(details)),
            $('<div class="selected-path"/>').append(
                $('<label for="file-browser-selected-file"/>').append(
                    "Selected File:", selected)))
        .appendTo("body");
    
    var translate = function (from, value, to) {
        var idPrefix       = browser.attr("id") + "-";
        var folderPrefix   = "folder-";
        var contentsPrefix = "contents-";
        var itemPrefix     = "item-";
        var path = from == "path" ? value : 
                    // Translate an ID to the corresponding path
                    value.replace("^#"+idPrefix,"")
                         .replace("^("+dirSuffix+"|"+contentsSuffix+"|"+itemPrefix+")", "")
                         .replace(/:-/g,"/")
                         .replace(/:_/g," ")
                         .replace(/:./g,"~");
        
        if(to == "path") return path;
        
        var baseID = path.replace(/~/g, ":.").replace(/ /g, ":_").replace(/\//g, ":-");
        
        if(to == "id") return baseID;
        
        var tokens = to.split(" ");
        var target = tokens.length > 0 ? tokens[0] : null;
        var type   = tokens.length > 1 ? tokens[1] : "id";
        var prefix, id, selector;
        
        switch(target) {
            case "contents":  prefix = idPrefix + contentsPrefix; break;
            case "folders":   prefix = idPrefix + folderPrefix;   break;
            case "item":      prefix = idPrefix + itemPrefix;     break;
            default:          prefix = idPrefix;                  break;
        }
        
        id       = prefix + baseID;
        selector = "#" + id.replace(/:/g,"\\:").replace(/\./g, "\\.");
        
        switch(type) {
            case "id":       return id;
            case "selector": return selector;
            case "element":  return $(selector);
            default:         return id;
        }
        return "";
    };
    
    var displayDirectory = function (path) {
        var directory = translate("path", path, "folders element");
        details.children("tbody").hide();
        directories.find("li").removeClass("expanded active").addClass("collapsed");
        directory.add(directory.parents("li")).removeClass("collapsed").addClass("expanded");
        directory.parent().addClass("active").focus();
        translate("path", path, "contents element").show();
    };
    
    var addDirectory = function (root, item) {
        var parent = translate("path", root, "folders element");
        $('<li class="collapsed">').attr("class", item.type)
            .append($("<a>")
                .attr({href:"#", rel:item.path})
                .html(item.name))
            .append($("<ul>").attr("id", translate("path", item.path, "folders id")))
            .appendTo(parent);
    };
    
    var addItem = function (table, item) {
        $("<tr>").attr("id", translate("path", item.path, "item id"))
            .append($('<td class="name">').addClass("class", item.type)
                        .append($('<a href="#">').attr("rel", item.path.replace(/^~\//, "")).html(item.name)),
                    $('<td class="date">').html(item.date))
            .appendTo(table);
    };
    
    var addProject = function (table, item) {
        $('<tr class="project">').attr("id", translate("path", item.path, "item id"))
            .append($('<td class="name">').addClass("class", item.type)
                        .append($('<a href="#">')
                                    .addClass(item.type)
                                    .attr("rel", item.path.replace(/^~\//, "")).html(item.name)
                                    .data(projectStore, item)),
                    $('<td class="date">').html(item.date))
            .appendTo(table);
    };
    
    var retrieveContents = function (path) {
        jQuery.getJSON(contentsSource, {
            p: path,
            t: browser.data(typeStore)
        }, function (data) {
            var dir    = data.base;
            var table = translate("path", dir, "contents element");
            if(table.length < 1) {
                table = $('<tbody>')
                    .attr("id", translate("path", dir, "contents id"))
                    .appendTo(details);
            }
            jQuery.each(data.contents, function(i,item) {
                if(item.type.indexOf("directory") >= 0) {
                    addDirectory(dir, item);
                } else if(item.type.indexOf("project") >= 0) {
                    addProject(table, item);
                } else {
                    addItem(table, item);
                }
            });
            table.addClass("loaded");
        });
    };
    
    var loadDeepContents = function (path) {
        var tokens = path.split("/");
        var parent = tokens[0];
        for(var i = 1; i <= tokens.length; i++) {
            if(!translate("path", parent, "contents element").hasClass("loaded")) {
                retrieveContents(parent);
            }
            parent += "/" + tokens[i];
        }
    };
    
    var showDirectory = function (dir) {
        var folder   = translate("path", dir, "folders element");
        var contents = translate("path", dir, "contents element");
        if(contents.hasClass("loaded")) {
            if(folder.parent().hasClass("active")) {
                contents.hide();
                folder.parent().addClass("collapsed").removeClass("expanded active");
            } else {
                displayDirectory(dir);
            }
        } else {
            retrieveContents(dir);
            displayDirectory(dir);
        }
    };
    
    var selectFile = function (file) {
        details.find("tr").removeClass("selected");
        file.parents("tr").addClass("selected");
        selected.val(file.attr("rel"));
        if(file.hasClass("project")) {
            selected.data(projectStore, file.data(projectStore));
        } else {
            selected.data(projectStore, null);
        }
    };
    
    var originalClasses = browser.attr("class");
    var openBrowser     = function(e) {
        var $this   = $(this);
        var project = $("#project");
        e.preventDefault();
        browser.attr("class", originalClasses)
               .addClass($this.attr("class"))
               .data(targetStore, $this.parent().children("input"))
               .data(typeStore, $this.attr("class"))
               .dialog("option", "title", $this.attr("title"))
               .dialog("open");
        if($this.attr("rel")) {
            showDirectory($this.attr("rel"));
        }
    };
    
    var closeBrowser = function () {
        browser.data(targetStore, null)
               .data(typeStore, null)
               .data(projectStore, null)
               .dialog("close");
        selected.val("");
        displayDirectory("/");
    };
    
    var chooseItem = function() {
        var dest = $(browser.data(targetStore));
        dest.val(selected.val());
        if(selected.data(projectStore)) {
            loadDeepContents(selected.data(projectStore).external);
            $("form.tool-setup").wiceProjectPresets(fields, selected.data(projectStore));
        } else {
            $("form.tool-setup").wiceProjectPresets(fields);
        }
        closeBrowser();
    };
    
        directories.attr("id", translate("path", "/", "folders id"))
        .delegate("a", "click", function(e) {
            e.preventDefault();
            showDirectory($(this).attr("rel"));
        });
    
    details.delegate("a", "click", function(e) {
        e.preventDefault();
        selectFile($(this));
    }).delegate("a", "dblclick", function(e) {
        e.preventDefault();
        selectFile($(this));
        chooseItem();
    });
    
    retrieveContents("/");

    browser.dialog({
        autoOpen: false,
        width:    790,
        modal:    true,
        position: ["center", "center"],
        buttons:  {
            "Cancel": closeBrowser,
            "Select File": chooseItem
        }
    });
    
    this.each(function(i, el){
        var $this = $(el);
        $this.children("a").click(openBrowser);
    });
};

})(jQuery);

